/*
Copyright (C) 2022-2024 Inspur Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package service

import (
	"icep/bean/entity"
	"icep/bean/model"
	"icep/bean/param"
	"icep/common/constant"
	"icep/common/crypto/gm"
	"icep/common/file"
	"icep/common/uuid"
	"icep/config"
	"os"
	"path/filepath"
	"time"
)

func (is *IcepService) IsBaasUserIdExist(baasUserId string) bool {
	var tenant entity.IcepTenant
	exist, err := is.DbEngine.Where("ibaas_user_id = ?", baasUserId).Get(&tenant)
	if err != nil {
		log.Errorf("query tenant by baasId error: %v", err)
		return false
	}
	return exist
}

func (is *IcepService) GetUserByBaasUserId(baasUserId string) *model.UserDetail {
	var tenant entity.IcepTenant
	exist, err := is.DbEngine.Where("ibaas_user_id = ?", baasUserId).Get(&tenant)
	if err != nil {
		log.Errorf("query tenant by baasId error: %v", err)
		return nil
	}
	if !exist {
		return nil
	}

	var user entity.IcepUser
	exist, err = is.DbEngine.Where("id = ?", tenant.Id).Get(&user)
	if err != nil {
		log.Errorf("query user by id error: %v", err)
		return nil
	}
	if !exist {
		return nil
	}

	userDetail := &model.UserDetail{
		Id:          user.Id,
		TenantId:    user.TenantId,
		UserType:    user.UserType,
		Phone:       user.Phone,
		Mail:        user.Mail,
		Password:    user.Password,
		Status:      user.Status,
		CreatedTime: user.CreatedTime.Format(constant.TimeLayout),
		UpdatedTime: user.UpdatedTime.Format(constant.TimeLayout),
	}
	return userDetail
}

func (is *IcepService) InitBaasUser(chainUserParam param.ChainUserParam) error {

	certPath, err := InitOrgCertsDir(chainUserParam.BaasUserId, chainUserParam.Domain, chainUserParam.OrgCert)
	if err != nil {
		log.Errorf("init baas user error: %v", err)
		return err
	}
	tenantId := uuid.Generate()
	now := time.Now()
	for _, consenser := range chainUserParam.Consensers {
		chainConsenser := entity.IcepChainConsenser{
			Id:          uuid.Generate(),
			TenantId:    tenantId,
			Name:        consenser.Name,
			Host:        consenser.Host,
			Port:        consenser.Port,
			CreatedTime: now,
			UpdatedTime: now,
		}
		_, err := is.DbEngine.InsertOne(&chainConsenser)
		if err != nil {
			log.Errorf("init baas user, init consenser error: %v", err)
			return err
		}
	}

	org := entity.IcepChainOrg{
		Id:          uuid.Generate(),
		TenantId:    tenantId,
		OrgName:     chainUserParam.OrgName,
		IamId:       chainUserParam.IamId,
		CryptoPath:  certPath,
		CreatedTime: now,
		UpdatedTime: now,
	}
	_, err = is.DbEngine.InsertOne(&org)
	if err != nil {
		log.Errorf("init baas user error, init org error: %v", err)
		return err
	}

	for _, inode := range chainUserParam.Inodes {
		chainNode := entity.IcepChainNode{
			Id:          uuid.Generate(),
			OrgId:       org.Id,
			Name:        inode.Name,
			Host:        inode.Host,
			Port:        inode.Port,
			CreatedTime: now,
			UpdatedTime: now,
		}
		_, err := is.DbEngine.InsertOne(&chainNode)
		if err != nil {
			log.Errorf("init baas user error, init node error: %v", err)
			return err
		}
	}

	identity := entity.IcepTenantIdentity{
		Id:          uuid.Generate(),
		TenantId:    tenantId,
		PrvKey:      chainUserParam.PrvKey,
		PubKey:      "",
		Cert:        chainUserParam.Cert,
		Status:      constant.IdentityStatusNormal,
		CreatedTime: now,
		UpdatedTime: now,
	}
	_, err = is.DbEngine.InsertOne(&identity)
	if err != nil {
		log.Errorf("init baas user error, init identity error: %v", err)
		return err
	}

	tenant := entity.IcepTenant{
		Id:           tenantId,
		IbaasUserId:  chainUserParam.BaasUserId,
		LeagueName:   chainUserParam.LeagueName,
		ChainName:    chainUserParam.ChainName,
		OrgName:      chainUserParam.OrgName,
		EnrollSecret: "",
		CreatedTime:  now,
		UpdatedTime:  now,
	}
	_, err = is.DbEngine.InsertOne(&tenant)
	if err != nil {
		log.Errorf("init baas user error, init tenant error: %v", err)
		return err
	}

	prvKeyHex, pubKeyHex, _ := gm.GenerateSM2Keys()
	sm4EcpPrvKey := gm.EncryptPrvKey(prvKeyHex)
	user := entity.IcepUser{
		Id:          tenantId,
		TenantId:    tenantId,
		UserType:    constant.UserTypeAdmin,
		Phone:       chainUserParam.Phone,
		Mail:        chainUserParam.Mail,
		Password:    config.Get("icep.default-pwd", constant.DefaultPwd),
		PrvKey:      sm4EcpPrvKey,
		PubKey:      pubKeyHex,
		Status:      constant.UserStatusNormal,
		CreatedTime: now,
		UpdatedTime: now,
	}
	_, err = is.DbEngine.InsertOne(&user)
	if err != nil {
		log.Errorf("init baas user error, init user error: %v", err)
		return err
	}

	return nil
}

func InitOrgCertsDir(baasId string, domain string, orgCert param.OrgCert) (string, error) {
	rootDir := config.Get("icep.certs-root-dir", constant.DefaultOrgCertRootDir)
	baasRootDir := filepath.Join(rootDir, baasId)
	iamDir := filepath.Join(baasRootDir, constant.DirIam)
	adminCertDir := filepath.Join(iamDir, constant.DirAdminCerts)
	caCertsDir := filepath.Join(iamDir, constant.DirCaCerts)
	certDir := filepath.Join(iamDir, constant.DirCert)
	tlsCaCertsDir := filepath.Join(iamDir, constant.DirTlsCaCerts)

	file.CreateIfNotExists(adminCertDir, true)
	file.CreateIfNotExists(caCertsDir, true)
	file.CreateIfNotExists(certDir, true)
	file.CreateIfNotExists(tlsCaCertsDir, true)

	err := file.Write(filepath.Join(adminCertDir, "admin@"+domain+".pem"), []byte(orgCert.AdminCert), os.ModePerm)
	if err != nil {
		return "", err
	}
	err = file.Write(filepath.Join(caCertsDir, "ca."+domain+".pem"), []byte(orgCert.CaCert), os.ModePerm)
	if err != nil {
		return "", err
	}

	err = file.Write(filepath.Join(certDir, "admin@"+domain+".pem"), []byte(orgCert.AdminCert), os.ModePerm)
	if err != nil {
		return "", err
	}

	err = file.Write(filepath.Join(certDir, "admin@"+domain+".key"), []byte(orgCert.AdminKey), os.ModePerm)
	if err != nil {
		return "", err
	}

	err = file.Write(filepath.Join(tlsCaCertsDir, "tlsca."+domain+".pem"), []byte(orgCert.TlsCaCert), os.ModePerm)
	if err != nil {
		return "", err
	}

	return iamDir, nil
}
